package com.onlyxiahui.framework.action.dispatcher.registry;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.onlyxiahui.framework.action.dispatcher.annotation.ActionMapping;
import com.onlyxiahui.framework.action.dispatcher.common.ActionMethod;
import com.onlyxiahui.framework.action.dispatcher.exception.MappingException;

/**
 * Date 2019-01-11 22:58:56<br>
 * Description
 * 
 * @author XiaHui<br>
 * @since 1.0.0
 */

public class ActionRegistry {

	private final Map<String, ActionMethod> actionMethodMap = new ConcurrentHashMap<>(16);
	private String separator = "";
	private boolean separateAlways = false;

	/**
	 * 为了更快获取要执行的action，将要执行的action加入Map进行缓存
	 * 
	 * @param classType
	 * @throws MappingException
	 */
	public void add(Class<?> classType) {
		Annotation[] as = classType.getAnnotations();
		ActionMapping am = null;
		for (Annotation annotation : as) {
			if (annotation instanceof ActionMapping) {
				am = ((ActionMapping) annotation);
				break;
			}
		}
		String value = null == am ? "" : am.value();
		saveMethod(value, classType);
	}

	/**
	 * 获取要执行的action的方法，并且缓存
	 * 
	 * @param classType
	 * @return
	 * @throws MappingException
	 */
	private void saveMethod(String code, Class<?> classType) {
		Method[] methods = classType.getMethods();
		if (null != methods && methods.length > 0) {
			for (Method method : methods) {
				Annotation[] as = method.getAnnotations();
				for (Annotation a : as) {
					if (a instanceof ActionMapping) {
						String value = ((ActionMapping) a).value();

						String path = getPath(code, value);

						if (actionMethodMap.containsKey(path)) {
							ActionMethod am = actionMethodMap.get(path);
							StringBuilder sb = new StringBuilder();
							sb.append(am.getActionClass().getName());
							sb.append("中的ActionMapping：");
							sb.append(am.getMethod().getName());
							sb.append("与");
							sb.append(classType.getName());
							sb.append("中的ActionMapping：");
							sb.append(method.getName());
							sb.append("存在重复");
							sb.append(path);
							sb.append("！");
							throw new MappingException(sb.toString());
						} else {
							actionMethodMap.put(path, new ActionMethod(classType, method));
						}
						break;
					}
				}
			}
		}
	}

	public void cover(Class<?> classType) {
		Annotation[] as = classType.getAnnotations();
		ActionMapping am = null;
		for (Annotation annotation : as) {
			if (annotation instanceof ActionMapping) {
				am = ((ActionMapping) annotation);
				break;
			}
		}
		String value = null == am ? "" : am.value();
		cover(value, classType);
	}

	public void cover(String code, Class<?> classType) {
		Method[] methods = classType.getMethods();
		if (null != methods && methods.length > 0) {
			for (Method method : methods) {
				Annotation[] as = method.getAnnotations();
				for (Annotation a : as) {
					if (a instanceof ActionMapping) {
						String value = ((ActionMapping) a).value();
						String path = getPath(code, value);
						actionMethodMap.put(path, new ActionMethod(classType, method));
						break;
					}
				}
			}
		}
	}

	/**
	 * 截取不包含包名，和小写首字母的类名
	 * 
	 * @param classType
	 * @return
	 */
	public String getSimpleNameAsProperty(Class<?> classType) {
		String valueName = classType.getSimpleName();
		return valueName = valueName.substring(0, 1).toLowerCase() + valueName.substring(1);
	}

	public Class<?> getClass(String path) {
		ActionMethod am = getActionMethod(path);
		return null == am ? null : am.getActionClass();
	}

	public ActionMethod getActionMethod(String path) {
		ActionMethod method = actionMethodMap.get(path == null ? "" : path);
		return method;
	}

	public ActionMethod getActionMethod(String classCode, String methodCode) {
		String path = getPath(classCode, methodCode);
		return getActionMethod(path);
	}

	public String getPath(String classCode, String methodCode) {
		StringBuilder sb = new StringBuilder();
		if (isSeparateAlways()) {
			sb.append(getSeparator());
		} else if (null != classCode && !classCode.isEmpty() && !classCode.startsWith(getSeparator())) {
			sb.append(getSeparator());
		}
		sb.append(classCode);
		if (isSeparateAlways()) {
			sb.append(getSeparator());
		} else if (!methodCode.startsWith(getSeparator())) {
			sb.append(getSeparator());
		}
		sb.append(methodCode);
		return sb.toString();
	}

	public String getSeparator() {
		return separator;
	}

	public void setSeparator(String separator) {
		this.separator = separator;
	}

	public boolean isSeparateAlways() {
		return separateAlways;
	}

	public void setSeparateAlways(boolean separateAlways) {
		this.separateAlways = separateAlways;
	}

	public void setSeparator(String separator, boolean separateAlways) {
		this.separator = separator;
		this.separateAlways = separateAlways;
	}
}
